package com.recharge.service.httpInterFace;

import com.alibaba.fastjson.JSONObject;
import com.recharge.common.result.ResultDO;
import com.recharge.common.result.ResultSupport;
import com.recharge.common.util.Constant;
import com.recharge.common.util.MD5Util;
import com.recharge.common.util.TemplateUtils;
import com.recharge.common.util.http.HttpClientUtil;
import com.recharge.domain.query.OrderStatusQueryDO;
import com.recharge.domain.vo.GoodsChannelDO;
import com.recharge.domain.vo.ProviderApiDO;
import com.recharge.domain.vo.ProviderCallbackDO;
import com.recharge.service.ProviderApiService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 赛浦优斯加油卡上游接口
 *
 * @author kui
 * @date 2020.11.16 14:29
 */
@Service
public class SaiPuYouSiHTTPImpl implements ProviderHTTPService {
    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    @Autowired
    ProviderApiService providerApiService;

    @Override
    public ResultDO commitOrder(GoodsChannelDO domain) {
        if (!verifyCommitParam(domain)) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                    , String.format("订单提交 >> 参数缺失 %s", domain.toString())
                    , "请求参数缺失"
                    , null);
        }

        ProviderCallbackDO callbackDO = new ProviderCallbackDO();
        callbackDO.setSerialNumber(domain.getProviderSerialNumber());
        callbackDO.setProviderId(domain.getProviderId());
        callbackDO.setOrderNo(domain.getOrderNo());
        callbackDO.setStatus(Constant.CALL_BACK_PROCESS);
        ResultDO result = providerApiService.addCallback(callbackDO);
        if (!result.isSuccess()) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                    , String.format("订单提交 >> 订单%s 添加存根信息失败", domain.getProviderSerialNumber())
                    , "添加回调存根信息失败"
                    , null);
        }


        //平台流水号
        String outTradeNo = domain.getProviderSerialNumber();
        //回调地址
        String backUrl = domain.getCallback();
        //供应商ID
        String account = domain.getUserId();
        //充值号码
        String cardNum = domain.getRechargeNumber();
        //商品编号
        String packages = domain.getProviderGoodsNo();
        //加油卡所属公司 1.中石油 2.中石化
        String packageType = "";
        //充值卡号对应手机号(上游表示随便填一个)
        String mobile = "12345678910";
        //供应商密钥
        String privateKey = domain.getPrivateKey();

        HashMap<String, String> map = new HashMap<>();
        map.put("account", account);
        map.put("card_num", cardNum);
        map.put("package", packages);

        //签名
        String afterSign = "";
        try {
            afterSign = MD5Util.md5(map, privateKey);
        } catch (Exception e) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                    , String.format("订单提交 >> 渠道商ID: %s HTTP请求参数构建失败", domain.getProviderId())
                    , "HTTP请求参数构建失败"
                    , null);
        }
        //请求参数
        map.put("action", "charge");
        map.put("v", "GC1.0.4");
        map.put("outtradeno", outTradeNo);
        map.put("backurl", backUrl);
        map.put("packagetype", packageType);
        map.put("mobile", mobile);
        map.put("sign", afterSign);

        // 发送请求
        logger.warn(String.format("订单提交 >> 发送GET请求(订单号%s): %s?%s", outTradeNo, domain.getRequestUrl(), map.toString()));
        String sendResult = HttpClientUtil.doGet(domain.getRequestUrl(), map);
        switch (sendResult) {
            case "500":
                return returnFail(false
                        , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                        , String.format("订单提交 >> 订单号 %s -> 订单提交供货商HTTP请求失败", outTradeNo)
                        , "HTTP请求失败"
                        , sendResult);
            case "504":
                return returnFail(false
                        , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                        , String.format("订单提交 >> 订单号 %s -> 订单提交供货商HTTP请求超时", outTradeNo)
                        , "HTTP请求超时"
                        , sendResult);
            case "":
                return returnFail(false
                        , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                        , String.format("订单提交 >> 订单号 %s -> 订单提交供货商HTTP请求没有返回信息", outTradeNo)
                        , "订单提交没有返回信息"
                        , sendResult);
        }
        logger.warn(String.format("订单提交 >> 请求返回信息: 订单号%s -> %s", outTradeNo, sendResult));

        // 解析请求返回结果转换为json对象
        JSONObject resultJson = new JSONObject();
        try {
            resultJson = JSONObject.parseObject(sendResult);
        } catch (Exception e) {
            logger.debug(String.format("订单提交 >> 请求返回结果解析json失败: %s", sendResult));
        }
        if (resultJson.size() == 0) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                    , String.format("订单提交 >> 订单号 %s -> 订单提交没有返回信息", outTradeNo)
                    , "没有返回信息"
                    , sendResult);
        }

        String status = null;
        String code = null;
        String desc = "";
        try {
            status = resultJson.get("response").toString();
            code = resultJson.get("msg").toString();
            desc = resultJson.get("data").toString();
        } catch (Exception e) {
            logger.debug(String.format("获取返回信息失败: 订单号%s -> %s", outTradeNo, sendResult));
        }
        if (code == null || status == null) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                    , String.format("订单提交 >> 订单号 %s -> 没有获取到返回状态码", outTradeNo)
                    , "订单提交没有返回状态码"
                    , sendResult);
        }

        if ("200".equals(status)) { //成功
            if ("1".equals(code)) {
                logger.debug(String.format("订单提交 >> 订单号 %s -> 订单提交成功|%s %s", outTradeNo, code, desc));
                result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.BUSINESS_RECHARGE_RETURN_STATUS_SUCCESS);
                result.setModel(ResultDO.SECOND_MODEL_KEY, "");
                return result;
            } else if ("0".equals(code)) {
                return returnFail(true
                        , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                        , String.format("订单提交 >> 订单号 %s -> 订单提交失败|%s %s", outTradeNo, code, desc)
                        , String.format("%s %s", desc, code)
                        , sendResult);
            } else {
                return returnFail(true
                        , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                        , String.format("订单提交 >> 订单号 %s -> 订单未知|%s %s", outTradeNo, code, desc)
                        , String.format("%s %s", desc, code)
                        , sendResult);
            }
        } else {//未知
            return returnFail(true
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                    , String.format("订单提交 >> 订单号 %s -> 订单未知|%s %s", outTradeNo, code, desc)
                    , String.format("%s %s", desc, code)
                    , sendResult);
        }
    }

    @Override
    public ResultDO backOrder(ProviderApiDO domain, String paramStr, String bodyStr) {
        ResultDO result = new ResultSupport();
        JSONObject jsonObject = null;
        try {
            jsonObject = JSONObject.parseObject(paramStr);
            logger.debug("订单异步回调 >> " + domain.getProviderNo() + "解析后数据: " + jsonObject.toJSONString());
        } catch (Exception e) {
            logger.debug("订单异步回调 >> " + domain.getProviderNo() + "解析json失败:" + paramStr);
        }
        if (jsonObject == null) {
            logger.debug("订单异步回调 >> 收到异步回调,但是没有回调信息");
            result.setModel(ResultDO.FIRST_MODEL_KEY, "fail");
            return result;
        }

        String serialNum, status, reportCode;
        try {
            //平台流水号
            serialNum = jsonObject.getString("outtradeno");
            //状态
            status = jsonObject.getString("status");
            //说明
            reportCode = jsonObject.getString("reportcode");
        } catch (Exception e) {
            logger.debug("订单异步回调 >> 获取返回结果异常" + e.getMessage());
            result.setSuccess(false);
            result.setModel(ResultDO.FIRST_MODEL_KEY, "fail");
            return result;
        }
//        //上游流水号
//        String orderNo = jsonObject.getString("inorder");
//        //充值账号
//        String username = jsonObject.getString("username");
//        //充值号码
//        String cardno = jsonObject.getString("cardno");
//        //该笔订单的实际扣款金额
//        String saleprice = jsonObject.getString("saleprice");
//        //充值凭证
//        String voutcher = jsonObject.getString("orderinfo");
//        //回调签名
//        String returnSign = jsonObject.getString("sign");
//
//        //加密前签名
//        String beforeVerifySign =
//                String.format("orderno=%s&inorder=%s&username=%s&cardno=%s&saleprice=%s&flag=%s&key=%s"
//                        , serialNum, orderNo, username, cardno, saleprice, status, domain.getPrivateKey());
//
//        String afterVerifySign = "";
//        try {
//            afterVerifySign = MD5Util.md5(beforeVerifySign, 32);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
////        logger.debug("签名验证: after >>"+afterVerifySign);
//        if (!afterVerifySign.equals(returnSign)) {
//            logger.debug("订单异步回调 >> 签名校验: 加密前 >>" + beforeVerifySign);
//            logger.debug(String.format("订单异步回调 >> 订单:%s 签名校验不一致 {本地签名:%s 返回签名:%s }", serialNum, afterVerifySign, returnSign));
//            result.setModel(ResultDO.FIRST_MODEL_KEY, "fail");
//            return result;
//        }

        //判断订单状态
        if (status.equals("4")) {
            logger.debug(String.format("订单异步回调 >> 订单异步返回:%s 成功 status: %s", serialNum, status));
            result = providerApiService.updateCallback(serialNum, "", "", Constant.CALL_BACK_SUCCESS);
        } else if (status.equals("5")) {
            logger.debug(String.format("订单异步回调 >> 订单异步返回:%s 失败 status: %s", serialNum, status));
            result = providerApiService.updateCallback(serialNum, "", "", Constant.CALL_BACK_FAIL);
        } else {
            logger.debug(String.format("订单异步回调 >> 订单异步返回:%s 未确认 status: %s %s", serialNum, status, reportCode));
            result = providerApiService.updateCallback(serialNum, "", "", Constant.CALL_BACK_NUKNOW);
        }
        if (!result.isSuccess()) {
            result.setModel(ResultDO.FIRST_MODEL_KEY, "fail");
            logger.debug("订单异步回调 >> 修改订单(" + serialNum + ")状态失败");
            return result;
        }

        result.setModel(ResultDO.FIRST_MODEL_KEY, "OK");
        return result;

    }

    @Override
    public ResultDO queryOrder(OrderStatusQueryDO domain) {
        ResultDO result = new ResultSupport();
        result.setSuccess(false);
        logger.debug("上游未提供订单查询接口");
        result.setModel(ResultDO.THIRD_MODEL_KEY, "上游未提供订单查询接口");
        return result;
    }

    @Override
    public ResultDO queryBalance(ProviderApiDO domain) {
        ResultDO result = new ResultSupport();
        if (domain.getPrivateKey() == null || domain.getUserId() == null) {
            result.setSuccess(false);
            logger.debug("余额查询 >> 没有查询到供货商信息配置");
            result.setModel(ResultDO.FIRST_MODEL_KEY, "查询失败");
            return result;
        }
        Map<String, String> requestParamMap = new HashMap<>();
        requestParamMap.put("account", domain.getUserId());
        requestParamMap.put("action", "getbalance");
        requestParamMap.put("v", "GC1.0.4");
        String sign = "";
        try {
            sign = MD5Util.md5(requestParamMap, domain.getPrivateKey());
        } catch (Exception e) {
            logger.debug("余额查询 >> 供应商账号: " + domain.getUserId() + " 签名加密失败" + e.getMessage());
            result.setSuccess(false);
            result.setModel(ResultDO.FIRST_MODEL_KEY, "查询失败");
            return result;
        }
        requestParamMap.put("sign", sign);

        // 发送请求
        String sendResult = HttpClientUtil.doGet(domain.getBalanceFindUrl(), requestParamMap);
        logger.debug(String.format("余额查询 >> 余额查询返回信息: 供应商账号 %s -> %s", domain.getUserId(), sendResult));

        // 解析请求返回结果转换为json对象
        JSONObject resultJson = new JSONObject();
        try {
            resultJson = JSONObject.parseObject(sendResult);
        } catch (Exception e) {
            logger.debug(String.format("余额查询 >> 请求返回结果解析JSON失败: %s", sendResult));
        }
        if (resultJson.size() == 0) {
            result.setSuccess(false);
            logger.debug(String.format("余额查询 >> 供应商账号: %s -> 余额查询没有返回信息", domain.getUserId()));
            result.setModel(ResultDO.FIRST_MODEL_KEY, "查询失败");
            return result;
        }
        String balance = null;
        if (resultJson.get("data") != null) {
            balance = resultJson.getString("data");
        }
//        String status = null;
//        String code = null;
//        try {
//            code = resultJson.getString("response");
//            status = resultJson.getString("msg");
//            balance = resultJson.getString("data");
//            if (resultJson.get("data") != null){
//                balance = resultJson.getString("data");
//            }
//        } catch (Exception e) {
//            logger.debug(String.format("余额查询 >> 获取返回信息失败: 供应商账号%s -> %s", domain.getUserId(), sendResult));
//        }
//        if (code == null || status == null) {
//            result.setSuccess(false);
//            logger.debug(String.format("余额查询 >> 供应商账号 %s -> 余额查询失败,没有返回状态码", domain.getUserId()));
//            result.setModel(ResultDO.FIRST_MODEL_KEY, "查询失败");
//            return result;
//        }

        result.setModel(ResultDO.FIRST_MODEL_KEY, Objects.requireNonNullElse(balance, "查询失败"));
        return result;

//        switch (code) {
//            case "0":
//                result.setModel(ResultDO.FIRST_MODEL_KEY, balance);
//                return result;
//            case "-1":
////                result.setSuccess(false);
//                logger.debug(String.format("余额查询 >> 供应商账号 %s -> 余额查询失败 | %s", domain.getUserId(), code));
//                result.setModel(ResultDO.FIRST_MODEL_KEY, "账号错误");
//                return result;
//            case "-9":
////                result.setSuccess(false);
//                logger.debug(String.format("余额查询 >> 供应商账号 %s -> 余额查询签名失败 | %s", domain.getUserId(), code));
//                result.setModel(ResultDO.FIRST_MODEL_KEY, "签名失败");
//                return result;
//            default:
////                result.setSuccess(false);
//                logger.debug(String.format("余额查询 >> 供应商账号 %s -> 余额查询 未知 | %s", domain.getUserId(), code));
//                result.setModel(ResultDO.FIRST_MODEL_KEY, "查询失败");
//                return result;
//        }

    }

    /**
     * 验证提交参数
     *
     * @param domain
     * @return boolean
     */
    private boolean verifyCommitParam(GoodsChannelDO domain) {
        // 流水号
        if (TemplateUtils.isEmpty(domain.getProviderSerialNumber())) {
            return false;
        }
        // 回调地址
        if (TemplateUtils.isEmpty(domain.getCallback())) {
            return false;
        }
        // 上游账号
        if (TemplateUtils.isEmpty(domain.getUserId())) {
            return false;
        }
        // 充值号码
        if (TemplateUtils.isEmpty(domain.getRechargeNumber())) {
            return false;
        }
        // 商品编号
        if (TemplateUtils.isEmpty(domain.getProviderGoodsNo())) {
            return false;
        }
        // 密钥
        if (TemplateUtils.isEmpty(domain.getPrivateKey())) {
            return false;
        }
        // 商户ID
        if (TemplateUtils.isEmpty(domain.getProviderId())) {
            return false;
        }

        return true;
    }

    /**
     * <h2>提交订单返回失败</h2>
     *
     * @param success    是否处理成功
     * @param code       订单状态
     * @param logMessage 失败信息
     * @param message    供货摘要
     * @param entity     返回信息字符串
     * @return FIRST_MODEL_KEY: 订单状态
     * SECOND_MODEL_KEY: 供货摘要
     * THIRD_MODEL_KEY: 上游返回信息字符串
     */
    private ResultDO returnFail(boolean success, int code, String logMessage, String message, String entity) {
        ResultDO result = new ResultSupport();
        result.setSuccess(success);
        result.setModel(ResultDO.FIRST_MODEL_KEY, code);
        result.setModel(ResultDO.SECOND_MODEL_KEY, message);
        result.setModel(ResultDO.THIRD_MODEL_KEY, entity);
        logger.debug(logMessage);
        return result;
    }
}
